package cn.felord.security.autoconfigure.util;

import cn.felord.security.autoconfigure.SecureUser;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

/**
 * The type Spring security authentication util.
 */
public final class AuthenticationUtil {

    /**
     * The constant anonymous.
     */
    public static final Authentication anonymous = new AnonymousAuthenticationToken("-1", "anonymousUser",
            AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
    /**
     * The constant ANONYMOUS_UID.
     */
    public static final String ANONYMOUS_UID = "-1";
    /**
     * The constant ANONYMOUS_CID.
     */
    public static final String ANONYMOUS_CID = "-1";
    /**
     * The constant UID_CLAIM.
     */
    public static final String UID_CLAIM = "uid";
    /**
     * The constant CID_CLAIM.
     */
    public static final String CID_CLAIM = "client_id";

    private AuthenticationUtil() {
    }

    /**
     * 获取当前用户，永远不可能为空
     *
     * @return the authentication
     */
    public static Authentication currentUser() {
        return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()).orElse(anonymous);
    }

    /**
     * Current user id string.
     *
     * @return the string
     */
    public static String currentUserId() {
        Authentication authentication = currentUser();
        if (authentication instanceof AnonymousAuthenticationToken) {
            return ANONYMOUS_UID;
        }

        if (authentication instanceof JwtAuthenticationToken) {
            JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
            return (String) jwtAuthenticationToken.getTokenAttributes().get(UID_CLAIM);
        }

        SecureUser user = (SecureUser) authentication.getPrincipal();
        return user.getUserId();
    }

    /**
     * Current client id string.
     *
     * @return the string
     */
    public static String currentClientId() {
        Authentication authentication = currentUser();
        if (authentication instanceof AnonymousAuthenticationToken) {
            return ANONYMOUS_CID;
        }

        if (authentication instanceof JwtAuthenticationToken) {
            JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
            return (String) jwtAuthenticationToken.getTokenAttributes().get(CID_CLAIM);
        }
        SecureUser user = (SecureUser) authentication.getPrincipal();
        return user.getClientId();
    }

    /**
     * Current user roles collection.
     *
     * @return the collection
     */
    public static Collection<? extends GrantedAuthority> currentUserRoles() {
        Collection<? extends GrantedAuthority> authorities = currentUser().getAuthorities();
        return CollectionUtils.isEmpty(authorities) ? Collections.emptyList() : authorities;
    }

    /**
     * Current user name string.
     *
     * @return the string
     */
    public static String currentUserName() {
        return currentUser().getName();
    }
}
